/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "lottie_render_nativewindow.h"
#include "boundscheck/securec.h"
#include "common/common.h"
#include <cstdint>
#include <native_buffer/native_buffer.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <unistd.h>
namespace LottieTurbo {

LottieRenderNativeWindow::LottieRenderNativeWindow()
{
    canvas_ = std::make_shared<drawing::Canvas>();
    bitmap_ = std::make_shared<drawing::Bitmap>();
}

std::shared_ptr<drawing::Canvas> LottieRenderNativeWindow::PrepareRender(OHNativeWindow *nativeWindow)
{
    if (!nativeWindow) {
        DRAWING_LOGE("LottieRenderNativeWindow::PrepareRender nativeWindow is nullptr");
        return nullptr;
    }
    // 设置窗口用途
    int32_t usage = NATIVEBUFFER_USAGE_CPU_READ | NATIVEBUFFER_USAGE_CPU_WRITE | NATIVEBUFFER_USAGE_MEM_DMA;
    if (OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_USAGE, usage) != 0) {
        DRAWING_LOGE("LottieRenderNativeWindow::PrepareRender Failed to set native window usage");
        return nullptr;
    }
    // 请求缓冲区
    if (OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &buffer_, &fenceFd_) != 0) {
        DRAWING_LOGE("LottieRenderNativeWindow::PrepareRender Failed to request native window buffer");
        return nullptr;
    }
    int retCode = -1;
    uint32_t timeout = 3000;
    if (fenceFd_ != -1) {
        struct pollfd pollfds = {0};
        pollfds.fd = fenceFd_;
        pollfds.events = POLLIN;
        do {
            retCode = poll(&pollfds, 1, timeout);
        } while (retCode == -1 && (errno == EINTR || errno == EAGAIN));
        close(fenceFd_); // 防止fd泄漏
        fenceFd_ = -1;
    }
    // 获取缓冲区句柄
    bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_);
    if (!bufferHandle_) {
        DRAWING_LOGE("LottieRenderNativeWindow::PrepareRender Failed to get buffer handle");
        return nullptr;
    }
    // 映射缓冲区
    mappedAddr_ = static_cast<uint32_t *>(
        mmap(bufferHandle_->virAddr, bufferHandle_->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle_->fd, 0));
    if (mappedAddr_ == MAP_FAILED) {
        DRAWING_LOGE("LottieRenderNativeWindow::PrepareRender Failed to mmap buffer");
        return nullptr;
    }

    OH_Drawing_BitmapFormat format{OH_Drawing_ColorFormat::COLOR_FORMAT_RGBA_8888,
                                   OH_Drawing_AlphaFormat::ALPHA_FORMAT_OPAQUE};
    bitmap_->Build(bufferHandle_->width, bufferHandle_->height, format);
    if (!bitmap_->get() || !canvas_->get()) {
        DRAWING_LOGE("LottieRenderNativeWindow:: Failed to create bitmap canvas");
        return nullptr;
    }
    // 使用原生API绑定bitmap到canvas
    canvas_->BindBitmap(bitmap_.get());

    // 转移所有权到成员变量
    return canvas_;
}

void LottieRenderNativeWindow::DisplayResult(OHNativeWindow *nativeWindow)
{
    if (!nativeWindow || !bitmap_.get() || !mappedAddr_ || mappedAddr_ == MAP_FAILED) {
        DRAWING_LOGE("LottieRenderNativeWindow::DisplayResult Invalid parameters for DisplayResult");
        return;
    }

    // 获取bitmap像素数据和尺寸
    void *bitmapAddr = OH_Drawing_BitmapGetPixels(bitmap_->get());
    uint32_t *value = static_cast<uint32_t *>(bitmapAddr);
    uint32_t *pixel = mappedAddr_;

    if (!value || !pixel) {
        DRAWING_LOGE("LottieRenderNativeWindow::DisplayResult Failed to get bitmap pixels");
        return;
    }

    // 获取bitmap的实际尺寸
    uint32_t bitmapWidth = bitmap_->GetWidth();
    uint32_t bitmapHeight = bitmap_->GetHeight();

    // 获取buffer的尺寸
    uint32_t bufferWidth = static_cast<uint32_t>(bufferHandle_->stride / 4);
    uint32_t bufferHeight = static_cast<uint32_t>(bufferHandle_->height);

    // 使用两者中较小的尺寸
    uint32_t width = std::min(bitmapWidth, bufferWidth);
    uint32_t height = std::min(bitmapHeight, bufferHeight);

    // 逐行复制像素数据
    for (uint32_t y = 0; y < height; y++) {
        auto err = memcpy_s(pixel + y * bufferWidth, width * sizeof(uint32_t), value + y * bitmapWidth,
                            width * sizeof(uint32_t));
        if (err != EOK) {
            DRAWING_LOGE("LottieRenderNativeWindow::DisplayResult memcpy_s Error");
        }
    }
    munmap(mappedAddr_, bufferHandle_->size);
    mappedAddr_ = nullptr;
    // 刷新缓冲区
    Region region{nullptr, 0};
    OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, buffer_, fenceFd_, region);
}

void LottieRenderNativeWindow::MunMap()
{
    munmap(mappedAddr_, bufferHandle_->size);
    mappedAddr_ = nullptr;
}

} // namespace LottieTurbo
